package com.leyou.search.service.impl;


import com.leyou.common.dto.PageDTO;
import com.leyou.common.exceptions.LyException;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.search.dto.SearchParamDTO;
import com.leyou.search.entity.Goods;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.service.SearchService;
import com.leyou.starter.elastic.dto.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.stream.Collectors;

import static com.leyou.search.constants.SearchConstants.*;

/**
 * @author 付
 */
//创建索引库
@Slf4j
@Service
@SuppressWarnings("ALL")
public class SearchServiceImpl implements SearchService {
    @Autowired
    private GoodsRepository repository;
    @Autowired
    private ItemClient itemClient;
    @Override
    public void createIndexAndMapping() {
        //删除索引库
        try {
            repository.deleteIndex();
        } catch (Exception e) {
           log.warn("索引库不存在，无需删除");
        }
        //创建索引库
        log.info("开始创建索引库");
        repository.createIndex(source_template);
        log.info("索引库创建完成");
    }

    //导入数据
    @Override
    public void loadData() {
        int page = 1, rows = 100;
        while (true) {
            log.info("开始导入第{}页数据", page);
            // 分页查询已经上架的spu
            PageDTO<SpuDTO> info = itemClient.querySpuByPage(page, rows, true, null, null, null);
            List<SpuDTO> spulist = info.getItems();

            // 遍历Spu集合，把SpuDTO通过buildGoods方法转为Goods
            List<Goods> goodsList = spulist.stream()
                    .map(this::buildGoods).collect(Collectors.toList());

            // 批量写入Elasticsearch
            repository.saveAll(goodsList);
            log.info("导入第{}页数据结束。", page);


            // 获取总页数
            Long totalPage = info.getTotalPage();
            // 判断是否还有spu没有查询
            if(page >= totalPage){
                // 没有则结束
                break;
            }
            // 翻页
            page++;
        }
    }

    //自动补全
    @Override
    public Mono<List<String>> getsuggestion(String key) {

        return repository.suggestBySingleField(suggestion_template,key);
    }

    //搜索商品的列表
    @Override
    public Mono<PageInfo<Goods>> searchGoodList(SearchParamDTO searchParamDTO) {
        //构建条件
        SearchSourceBuilder builder=new SearchSourceBuilder();
        //source过滤
        builder.fetchSource(DEFAULT_SOURCE_FIELD,null);
        //query条件
        String key = searchParamDTO.getKey();
        if (StringUtils.isBlank(key)){
            throw new LyException(404,"没有找到相关的商品");
        }
        builder.query(QueryBuilders.boolQuery().must(QueryBuilders.matchPhraseQuery(DEFAULT_SEARCH_FIELD,key)));
        //sort排序
        String sortBy = searchParamDTO.getSortBy();
        if (StringUtils.isNotBlank(sortBy)){
            builder.sort(sortBy,searchParamDTO.getDesc()? SortOrder.DESC:SortOrder.ASC);
        }
        //分页
        builder.from(searchParamDTO.getFrom()).size(searchParamDTO.getSize());
        //高亮
        builder.highlighter(new HighlightBuilder().field(DEFAULT_SEARCH_FIELD).preTags(DEFAULT_PRE_TAG).postTags(DEFAULT_POST_TAG));


        return repository.queryBySourceBuilderForPageHighlight(builder);

    }

    //新增
    @Override
    public void saveItemBySpuId(Long spuid) {
        SpuDTO spu = itemClient.queryGoodsById(spuid);
        Goods goods = buildGoods(spu);
        repository.save(goods);
    }

    //删除
    @Override
    public void deleteItemBySpuId(Long spuid) {
        repository.deleteById(spuid);
    }

    //数据导入
    private Goods buildGoods(SpuDTO spuDTO) {
        //商品标题，原有标题拼接分类品牌信息
        String title =spuDTO.getTitle()+spuDTO.getBrandName()+spuDTO.getCategoryName();
        // 自动补全字段获取
        Set<String> suggestion = new HashSet<>();
        suggestion.add(spuDTO.getName());
        suggestion.add(spuDTO.getBrandName());
        Collections.addAll(suggestion,spuDTO.getCategoryName().split("/"));

        //查询除规格参数的name和value
        List<SpecParamDTO> params = itemClient.querySpecsValues(spuDTO.getId(), true);
        //准备specs集合
        List<Map<String,Object>>specs=new ArrayList<>();
        for (SpecParamDTO param : params) {
            Map<String,Object>map=new HashMap<>(2);
            map.put("name",param.getName());
            map.put("value",param.getValue());
            specs.add(map);
        }
        //sku
        List<SkuDTO> skulist = spuDTO.getSkus();
        Long sold=0L;
        if (CollectionUtils.isEmpty(skulist)){
            //查询sku
           skulist= itemClient.querySkuBySpuId(spuDTO.getId());
        }

        Set<Long>prices=new TreeSet<>();
        for (SkuDTO skuDTO : skulist) {
            sold+=skuDTO.getSold();
            prices.add(skuDTO.getPrice());
        }
        //取一张图片
        String image = StringUtils.substringBefore(skulist.get(0).getImages(), ",");

        //封装goods
        Goods goods = new Goods();
        goods.setUpdateTime(new Date());
        goods.setTitle(title);
        goods.setSuggestion(suggestion);
        goods.setSpecs(specs);
        goods.setSold(sold);
        goods.setPrices(prices);
        goods.setImage(image);
        goods.setId(spuDTO.getId());
        goods.setCategoryId(spuDTO.getCid3());
        goods.setBrandId(spuDTO.getBrandId());


        return goods;
    }

}
